<?php

namespace App\Exports;

use App\Models\AfterSaleOrder;
use App\Models\Agent;
use App\Models\Base;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataType;

class AfterSaleOrderExport extends BaseExport implements WithCustomValueBinder, FromQuery
{
    public function __construct(\Illuminate\Http\Request $request = null)
    {
        parent::__construct($request);

        activity()
            ->by(\Auth::user())
            ->withProperty('ip', app('request')->ip())
            ->log(sprintf('导出售后订单'));
    }

    public function headings(): array
    {
        return [
            '售后编号',
            '商品编号',
            '活动编号',
            '供应商',
            '代理名称',
            '代理级别',
            '代理手机号',
            '商品名称',
            '售后类型',
            '相关订单',
            '收件人姓名',
            '收件人手机号',
            '收件人地址',
            '发货单号',
            '重发货商品明细',
            '状态',
            '申请时间',
            '金额',
            '总进价成本',
            '退货单号',
            '退货款',
            '退运费',
            '补偿款',
            '补偿款提交原因',
            '意见内容',
            '处理人',
            '处理时间',
            '售后凭证(图片)',
            '售后凭证(视频)',
            '重发货快递单号'
        ];
    }

    public function map($row): array
    {
        $row = $row->toArray();

        $amount = 0;
        switch ($row['type']) {
            case AfterSaleOrder::TYPE_RETURN:
                $amount = array_reduce($row['after_sale_order_skus'], fn($total, $current) => $total + $current['amount'] * $current['unit_price'], 0);
                break;
            case AfterSaleOrder::TYPE_HEAVY_SHIPMENT:
                // 重发货不涉及金额
                break;
            case AfterSaleOrder::TYPE_REFUND_ONLY:
                $amount = $row['refund_amount'];
                break;
            case AfterSaleOrder::TYPE_MAKE_UP:
                $amount = $row['compensation'];
                break;
        }

        $totalPurchaseCost = 0; // 总进价成本
        foreach (($row['after_sale_order_skus'] ?? []) as $item) {
            // 系统字段
            $systemFiledData = Arr::only($item['sku_snapshot'], ['direct_invitation', 'elite_price', 'entry_price', 'external_guide_price', 'group_owner_price', 'indirect_invitation', 'strongman_price', 'purchase_price']);
            $totalPurchaseCost += $systemFiledData['purchase_price'] * $item['amount']; // 累加总进价成本
            // 格式化
            $systemFiledData = array_map(fn($value) => number_format($value / Base::CURRENCY_UNIT_CONVERSION, 2), $systemFiledData);
            // 数量
            $systemFiledData['amount'] = $item['amount'];
            // sku 自定义数据
            $systemFiledData['detail'] = []; // 明细
            foreach ($item['sku_snapshot']['values'] as $value) {
                $systemFiledData[$value['attribute_id']] = $value['content'];
                $systemFiledData['detail'][] = $value['content'] . ' * ' . $item['amount'];
            }
        }

        return [
            $row['numbering'], // 售后编号
            $row['order']['commodity_numbering'], // 商品编号
            $row['order']['commodity_activity_snapshot']['numbering'], // 活动编号
            $row['supplier']['name'] ?? '', // 供应商
            $this->removeUncommonWords($this->removeEmoji($row['agent']['name'])), // 代理名称
            Agent::LEVEL_MAP[$row['agent']['level']]['text'], // 代理级别
            $row['agent']['phone'], // 代理手机号
            $row['order']['commodity_name'], // 商品名称
            AfterSaleOrder::TYPE_MAP[$row['type']], // 售后类型
            $row['order_numbering'], // 相关订单
            $this->removeUncommonWords($this->removeEmoji($row['order']['client_name'] ?? '')), // 收件人姓名
            $row['order']['client_phone'], // 收件人手机号
            $this->removeUncommonWords($this->removeEmoji($row['address'])), // 收件人地址
            implode('; ', array_map(fn($courierInformation) => $courierInformation['tracking_numbering'], $row['order']['courier_information'])), // 发货单号
            $row['type'] === AfterSaleOrder::TYPE_HEAVY_SHIPMENT ? implode('; ', $systemFiledData['detail']) : '', // 重发货商品明细
            AfterSaleOrder::STATUS_MAP[$row['status']], // 状态
            $row['created_at'], // 申请时间
            number_format($amount / 100, 2), // 金额
            number_format($totalPurchaseCost / 100, 2), // 总进价成本
            $this->removeUncommonWords($this->removeEmoji($row['return_order_numbering'])), // 退货单号
            number_format($row['refund_amount'] / 100, 2), // 退货款
            number_format($row['refund_shipping'] / 100, 2), // 退运费
            number_format($row['compensation'] / 100, 2), // 退运费
            $this->removeUncommonWords($this->removeEmoji($row['reason'])), // 提交原因
            $row['audit'][0]['audit_remarks'] ?? '', // 意见内容
            $row['audit'][0]['administrator']['real_name'] ?? '', // 处理人
            $row['audit'][0]['created_at'] ?? '', // 处理时间
            implode('; ',
                array_map(
                    fn($attachment) => $attachment['url'],
                    array_filter($row['attachments'] ?? [], fn($att) => $att['pivot']['type'] === AfterSaleOrder::ATTACHMENT_TYPE_PICTURE)
                )
            ),// 售后凭证(图片)
            implode('; ',
                array_map(
                    fn($attachment) => $attachment['url'],
                    array_filter($row['attachments'] ?? [], fn($att) => $att['pivot']['type'] === AfterSaleOrder::ATTACHMENT_TYPE_VIDEO)
                )
            ),// 售后凭证(视频)
            implode('; ',
                array_map(
                    fn($courierInformation) => ($courierInformation['courier_company']['name'] ?? '') . ':' . ($courierInformation['tracking_numbering'] ?? ''),
                    $row['courier_information'] ?? []
                )
            ), // 重发货快递单号
        ];
    }

    /**
     * @return \Illuminate\Database\Query\Builder
     */
    public function query()
    {
        return AfterSaleOrder::query()
            ->with(['supplier', 'order.courierInformation', 'agent', 'afterSaleOrderSkus', 'audit.administrator', 'courierInformation.courierCompany', 'attachments'])
            ->when($this->request['numbering'] ?? '', function (Builder $builder, $cond) {
                $builder->where('after_sale_orders.numbering', $cond);
            })
            ->when($this->request['order_numbering'] ?? '', function (Builder $builder, $cond) {
                $builder->where('after_sale_orders.order_numbering', $cond);
            })
            ->when($this->request['commodity_numbering'] ?? '', function (Builder $builder, $cond) {
                $builder
                    ->join('commodities', 'commodities.id', '=', 'after_sale_orders.commodity_id')
                    ->where('commodities.numbering', $cond);
            })
            ->when($this->request['commodity_activity_numbering'] ?? '', function (Builder $builder, $cond) {
                $builder
                    ->join('commodity_activities', 'commodity_activities.id', '=', 'after_sale_orders.commodity_activity_id')
                    ->where('commodity_activities.numbering', $cond);
            })
            ->when($this->request['commodity_id'] ?? 0, function (Builder $builder, $cond) {
                $builder->where('after_sale_orders.commodity_id', $cond);
            })
            ->when($this->request['commodity_activity_id'] ?? 0, function (Builder $builder, $cond) {
                $builder->where('after_sale_orders.commodity_activity_id', $cond);
            })
            ->when($this->request['tracking_numbering'] ?? '', function (Builder $builder, $cond) {
                $builder
                    ->join('courier_information', 'courier_information.deliverable_id', '=', 'after_sale_orders.id')
                    ->where(function (Builder $builder) use ($cond) {
                        $builder
                            ->where('courier_information.deliverable_type', 'App\Models\AfterSaleOrder')
                            ->where('courier_information.tracking_numbering', 'like', "$cond%");
                    });
            })
            ->when($this->request['client_search'] ?? '', function (Builder $builder, $cond) {
                $builder
                    ->join('orders', 'after_sale_orders.order_id', '=', 'orders.id')
                    ->where(function (Builder $builder) use ($cond) {
                        $builder
                            ->where('orders.client_phone', 'like', "$cond%")
                            ->orWhere('orders.client_name', 'like', "$cond%");
                    });
            })
            ->when($this->request['supplier_search'] ?? '', function (Builder $builder, $cond) {
                $builder
                    ->join('suppliers', 'after_sale_orders.supplier_id', '=', 'suppliers.id')
                    ->where(function (Builder $builder) use ($cond) {
                        $builder
                            ->where('suppliers.name', 'like', "$cond%");
                    });
            })
            ->when($this->request['agent_search'] ?? '', function (Builder $builder, $cond) {
                $builder
                    ->join('agents', 'after_sale_orders.agent_id', '=', 'agents.id')
                    ->where(function (Builder $builder) use ($cond) {
                        $builder
                            ->where('agents.phone', 'like', "$cond%")
                            ->orWhere('agents.name', 'like', "$cond%");
                    });
            })
            ->when($this->request['status'] ?? 0, function (Builder $builder, $cond) {
                $builder->where('after_sale_orders.status', $cond);
            })
            ->when($this->request['type'] ?? 0, function (Builder $builder, $cond) {
                $builder->where('after_sale_orders.type', $cond);
            })
            ->when($this->request['created_at_begin'] ?? '', function (Builder $query, $createdAtBegin) {
                $query->where('after_sale_orders.created_at', '>=', $createdAtBegin);
            })
            ->when($this->request['created_at_end'] ?? '', function (Builder $query, $createdAtEnd) {
                $query->where('after_sale_orders.created_at', '<=', Carbon::parse($createdAtEnd)->endOfDay());
            })
            ->select(['after_sale_orders.*']);
    }

    public function bindValue(Cell $cell, $value)
    {
        if (is_numeric($value) && !in_array($cell->getColumn(), ['R', 'S', 'U', 'V', 'W'])) { // 金额保持数字
            $cell->setValueExplicit($value, DataType::TYPE_STRING);

            return true;
        }

        // else return default behavior
        return parent::bindValue($cell, $value);
    }
}
